package algorithms;
import infoPackage.*;

import java.util.ArrayList;


//http://www.softtechdesign.com/GA/GA-Javadocs/com/softtechdesign/ga/GAString.html

public class Chromosome {

	float ps = -1;  // Selection Probability
	float pcr = -1; // Crossover Probability
	float pm = -1;  // Mutation Probability
	
	/** Maximum of dams to construct in the same river */
	public static int maxDam =  3; 
	
	/** Minimum of distance, in km, necessary between 2 dams*/
	public static float minDistance = 3;
	
	/** Helps in selection task */
	private boolean selected = false;	
	
	private int crossover = -1;				// Point to cross the chromosomes
	private int mutation = -1;				// Value to mutate
	private float value = Float.MIN_VALUE;	// Adaptation Function Value
	
	public ArrayList<Dam> chromosome = new ArrayList<Dam>();

	public Chromosome(){}
	
	public Chromosome(int size){
		for(int i=0; i<size; i++){
			boolean construct = Dam.randomConstruct();
			float capacity = Dam.randomCapacity();
			float volume = Dam.randomVolume();
			int tecnology = Dam.randomTecnology();
			int natureImpact = Dam.randomNatureImpact();
			ArrayList<Material> mat = Dam.randomMaterials();
			chromosome.add( new Dam(construct, capacity, volume, tecnology, natureImpact, mat));
		}		
	}
	
	public void adaptationFunction(ArrayList<Section> sections){
		int totalDam = 0; 	// total number of dams to be constructed
		int river = -1; 	// id of the river
		for (int i= 0; i < chromosome.size(); i++){
			Dam dam = chromosome.get(i);
			Section section = sections.get(i);
			
			if (dam.isConstruct()){
				//No connection to power
				if (!section.power){  
					this.value = 0;
					return;
				}else{
									
					if (river == -1 || river == section.river ){
						totalDam++;
						// Two dams in the same river must be at least a minDistance between them.
						// requires an ordered file. the sections must follow an increasing order of offset
						if( i>0 && section.offset < (sections.get(i-1).offset + minDistance)){
							this.value = 0;
							return;
						}						
					}else{
						// No more than maxDam dams shall be constructed in the same river
						if( totalDam == 0 || totalDam > maxDam){
							this.value = 0;
							return;
						}
						totalDam = 1;
					}
					river = section.river;
					//the damn must be a minimum volume, defined in the file, for each section 
					if(dam.getVolume() < section.minVolume){
						this.value = 0;
						return;
					}
					
					//Price of the components
					float component_price = 0;
					for(int j=0; j< dam.materials.size(); j++){
						Material mat = dam.materials.get(j);
						component_price += dam.getVolume() * mat.getPercentage() * mat.getPrice();
					}					
					
					// need for an extra structure - fish stairway
					if (section.struct) component_price += 1000;	
					
					//component_price += natureValue(dam.getNatureImpact());
					component_price += tecnologyValue(dam.getTecnology());
					
					//Price of the field
					float field_price = section.cost * section.size;
					
					float field_quality = section.h * 10000 /section.narrow + accessValue(section.access)
											- 40*floatValue(section.flora) - 60*floatValue(section.fauna) 
											+ section.people + natureValue(dam.getNatureImpact());
					
					float efficiency = dam.getCapacity()*dam.getTecnology() / (section.flow * section.h) * 10000000  ;
					if(efficiency < 0.5){
						this.value = 0;
						return;
					}
					
					System.out.println(" EF:" + efficiency +
										"   Comp price:" + component_price + 
										"\nField quality: " + field_quality + 
										"   Price: " + field_price +
										"   q/p: " + field_quality/field_price + "\n");
					
					this.value += efficiency / (component_price + (field_quality/ field_price));
				}
			}
			else{
				this.value += 0;
			}

		}
		System.out.println(" Value: " + this.value);
	}	
	public int floatValue(boolean b){
		return	b ? 1 : 0;
	}
	
	public int natureValue(int n){
		switch(n){
			case 0:
				return 200;
			case 1:
				return 100;
			case 2:
				return 0;
			case 3:
				return -100;
			case 4:
				return -200;
			default:
				return 10;
		}
	}
	
	public int accessValue(int n){
		switch(n){
			case 0: //muito mau
				return -300;
			case 1: //mau
				return -150;
			case 2:	//normal
				return 0;
			case 3://bom
				return 150;
			case 4://muito bom
				return 300;
			default:
				return 1;
		}
	}
	
	public int tecnologyValue(int n){
		switch(n){
			case 1: //mau
				return 1000;
			case 2:	//normal
				return 2000;
			case 3://bom
				return 3000;
			case 4://muito bom
				return 10000;
			default:
				return 50;
		}
	}
	
	
	public void printChromosome(){
		for(int i=0; i< chromosome.size(); i++){
			Dam d =  chromosome.get(i);
			System.out.print( " Dam " + i + 
								" | Construct: " + d.isConstruct() + 
								" | Capacity: " + d.getCapacity() +
								" | Volume: " + d.getVolume() +
								" | Nature: " + d.getNatureImpact() +
								" | Tecnology: " + d.getTecnology() 
								);
			System.out.println(" | Materials: ");
			for(int j= 0; j<d.getMaterials().size(); j++)
				d.getMaterials().get(j).printMaterial();
		
		}
	}

	/**
	 * @param value the value to set
	 */
	public void setValue(float value) {
		this.value = value;
	}

	/**
	 * @return the value
	 */
	public float getValue() {
		return value;
	}

	/**
	 * @param selected the selected to set
	 */
	public void setSelected(boolean selected) {
		this.selected = selected;
	}

	/**
	 * @return the selected
	 */
	public boolean isSelected() {
		return selected;
	}
	

	/**
	 * @param crossover the crossover to set
	 */
	public void setCrossover(int crossover) {
		this.crossover = crossover;
	}

	/**
	 * @return the crossover
	 */
	public int getCrossover() {
		return crossover;
	}

	/**
	 * @param mutation the mutation to set
	 */
	public void setMutation(int mutation) {
		this.mutation = mutation;
	}

	/**
	 * @return the mutation
	 */
	public int getMutation() {
		return mutation;
	}
}
